package com.rparoxysm.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

/* Class to aid in debugging.
 *
 * Available fields.  Each can selectively be turned on or off (except message):
 *      Thread name
 *      Timestamp
 *      Class name
 *      Scope
 *      Debug Level
 *      Message
 */

public class Debug {
    public static final int ALL   = 0;
    public static final int INFO  = 1;
    public static final int TRACE = 3;
    public static final int DEBUG = 5;
    public static final int LOG   = 7;
    public static final int WARN  = 8;
    public static final int ERROR = 9;

    private static final String[] DEBUG_LEVEL_NAMES = { "ALL",     // 0
                                                        "INFO",    // 1
                                                        "",        // 2
                                                        "FLOW",    // 3
                                                        "",        // 4
                                                        "DEBUG",   // 5
                                                        "",        // 6
                                                        "LOG",     // 7
                                                        "WARN",    // 8
                                                        "ERROR" }; // 9
                                                        
    private static int DEFAULT_LEVEL = ERROR;
    public static void setDefaultLevel(int level) {
        DEFAULT_LEVEL = level;
    }

    private static String MESSAGE_INTRO = new String(" - ");

    private String scope;
    private DebugPrinter printer;

    /** Fields to display in the debug output */
    private boolean _showThread;  /** Name of the thread where executed */
    private boolean _showTime;    /** Timestamp of the debug message */
    private boolean _showClass;   /** Class name containing the debug handle */
    private boolean _qualifyClass;/** Should class name be fully qualified */
    private boolean _showScope;   /** User assigned scope of the debug handle */
    private boolean _showLevel;   /** Debug level associated with a message */
    private boolean[] _showDebugLevel;/** Optionally display individual levels */
    private Debug(String scope) {
	this.scope = new String(scope);
	DebugControl.getControl().register(this);
	setLevel(DEFAULT_LEVEL);
    }

    public static Debug init(String scope) {
	Debug handle = DebugControl.getControl().getHandle(scope);
	if(scope == null) {
	    handle = new Debug(scope);
	}

	return handle;
    }

    public synchronized void print(int level, String message) {
        if(_showDebugLevel[level] == true) {
            boolean first = true;  // indicator to print leading ":"
            
            // Build up the string to send the DebugPrinter
            String info = new String();

            // display the thread name
            if(_showThread) {
                info += (first ? "[" : ":") + Thread.currentThread().getName();
                first = false;
            }

            // display the time stamp
            if(_showTime) {
		Calendar dtg = new GregorianCalendar();
		SimpleDateFormat sdf = 
		    new SimpleDateFormat("dd HH:mm:ssz MM YY"); 
                info += (first ? "[" : ":") + sdf.format(dtg.getTime());;
                first = false;
            }
            
            // display the scope
            if(_showScope) {
                info += (first ? "[" : ":") + scope;
                first = false;
            }

            // display the class name
            if(_showClass) {
                String className = 
		    this.getClass().getDeclaringClass().getName();
                
                if(_qualifyClass == false) {
                    // split the fully qualified name by "." and use last part
		    className = className.substring(className.lastIndexOf('.'));
                }
                info += (first ? "[" : ":") + className;
                first = false;
            }

            // display the debug level
            if(_showLevel) {
                info += (first ? "[" : ":") + DEBUG_LEVEL_NAMES[level];
            }

            if(first == false) {
                info += "]";
            }

            printer.println(info + MESSAGE_INTRO + message);
        }
    }

    /** The show* methods selectively display different fields when printing */
    
    public synchronized void showThreadName(boolean show) {
        _showThread = show;
    }

    public synchronized void showClassName(boolean show) {
        _showClass = show;
    }

    public synchronized void fullyQualifiedClassNames(boolean show) {
        _qualifyClass = show;
    }

    public synchronized void showScope(boolean show) {
        _showScope = show;
    }
    
    public synchronized void showLevel(boolean show) {
        _showLevel = show;
    }

    /** The set* methods set individual levels of the debug handle */
    public synchronized void setLevel(int level) {
        for(int i = 0; i < _showDebugLevel.length; ++i) {
            _showDebugLevel[i] = (i >= level);
        }
    }
    
    public synchronized void setDebugLevel(int level, boolean show) {
        if(level >= 0 && level < _showDebugLevel.length) {
            _showDebugLevel[level] = show;
        }
    }

    public synchronized String getScope() {
        return scope;
    }
}
